#pragma once
namespace graph_basic
{
   namespace details
   {
   
   }
struct view_vertex_iterator_t;
struct view_edge_iterator_t;
struct view_adj_edges_iterator_t;
struct view_adj_vertices_iterator_t;

typedef std::pair<view_vertex_iterator_t, view_vertex_iterator_t> view_vertex_iterator_pair_t;
typedef std::pair<view_edge_iterator_t, view_edge_iterator_t> view_edge_iterator_pair_t;
typedef std::pair<view_adj_edges_iterator_t, view_adj_edges_iterator_t> view_adj_edges_iterator_pair_t;
typedef std::pair<view_adj_vertices_iterator_t, view_adj_vertices_iterator_t> view_adj_vertices_iterator_pair_t;

template<>
struct graph_traits<graph_view_t>
{
   typedef view_vertex_iterator_t vertex_iterator;
   typedef view_edge_iterator_t edge_iterator;
   typedef view_adj_vertices_iterator_t adj_vertices_iterator;
   typedef view_adj_edges_iterator_t adj_edges_iterator;
};

struct view_vertex_iterator_t: public std::forward_iterator_tag
{
   void operator ++ ();
   vertex_t const & operator * () const;
   vertex_t& operator * ();
   bool operator != (view_vertex_iterator_t const & right);    
private:
   view_vertex_iterator_t(graph_view_t& view, vertex_iterator_pair_t its);
   view_vertex_iterator_t(vertex_iterator_t it)
      :  it_pair_(it, it)
   {}
   vertex_iterator_pair_t it_pair_;
   graph_view_t* view_;
   friend view_vertex_iterator_pair_t vertices(graph_view_t& view);
};

struct view_edge_iterator_t: public std::forward_iterator_tag
{
   void operator ++ ();
   edge_t const operator * () const;
   edge_t operator * ();
   bool operator != (view_edge_iterator_t const & right) const;
private:
   view_edge_iterator_t(graph_view_t& view, edge_iterator_pair_t its);
   view_edge_iterator_t(edge_iterator_t it)
      :  it_pair_(it, it)
   {}
   edge_iterator_pair_t it_pair_;
   graph_view_t* view_;
   friend view_edge_iterator_pair_t edges(graph_view_t& view);
};


struct view_adj_edges_iterator_t: public std::forward_iterator_tag
{
   void operator ++ ();
   edge_t const operator * () const;
   edge_t operator * ();
   bool operator != (view_adj_edges_iterator_t const & right) const;
private:
   view_adj_edges_iterator_t(vertex_id_t source_id, graph_view_t& view, adj_edges_iterator_pair_t its);
   view_adj_edges_iterator_t(adj_edges_iterator_t it)
      :it_pair_(it, it)
   {}
   adj_edges_iterator_pair_t it_pair_;
   graph_view_t* view_;
   friend view_adj_edges_iterator_pair_t adj_edges(vertex_id_t source_v_id, graph_view_t& view);
};

struct view_adj_vertices_iterator_t: public std::forward_iterator_tag
{
   void operator ++ ();
   vertex_t const & operator * () const;
   vertex_t& operator * ();
   bool operator != (view_adj_vertices_iterator_t const & right);
private:
   view_adj_vertices_iterator_t(vertex_id_t source_v_id, graph_view_t& view, adj_edges_iterator_pair_t its);
   view_adj_vertices_iterator_t(adj_edges_iterator_t it)
      :  it_pair_(it, it)
   {}
   adj_edges_iterator_pair_t it_pair_;
   graph_view_t* view_;
   friend view_adj_vertices_iterator_pair_t adj_vertices(vertex_id_t source_v_id, graph_view_t& view);
};

view_vertex_iterator_pair_t vertices(graph_view_t& view);
view_edge_iterator_pair_t edges(graph_view_t& view);
view_adj_edges_iterator_pair_t adj_edges(vertex_id_t source_v_id, graph_view_t& view);
view_adj_vertices_iterator_pair_t adj_vertices(vertex_id_t source_v_id, graph_view_t& view);
}